package com.cn.qtms.base.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cn.qtms.base.entity.BaseEntity;
import com.cn.qtms.base.service.BaseService;
import com.cn.qtms.common.page.PageReq;
import com.cn.qtms.common.page.PageRes;
import com.cn.qtms.common.page.QueryCondition;
import com.cn.qtms.common.result.QueryParam;
import com.cn.qtms.common.result.Result;
import com.cn.qtms.common.result.ResultUtil;
import com.cn.qtms.exception.AppException;
import com.cn.qtms.exception.ApplicationException;
import com.cn.qtms.util.BeanConvertUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.*;

/**
 * @Name:BaseServiceImpl
 * @Description: 基础业务接口实现
 * @Author: Neil
 * @Date: 2019-08-21 16:06
 **/
@Slf4j
@Service
public abstract class BaseServiceImpl<T extends BaseEntity, ID> extends BaseJpaServiceImpl<T, ID> implements BaseService<T, ID> {

    /**
     * list和page暂时不加缓存
     * @param request
     * @return
     */
    @Override
    public Result<PageRes<T>> page(QueryParam request) {
        PageReq pageReq = preBuildCriteria(request);
        List<QueryCondition> criteria = buildCriteria(request);
        //默认查询未删除
        QueryCondition condition = QueryCondition.eq(BaseEntity.IS_DELETE, false);
        criteria.add(condition);
        long count = super.count(criteria);
        Page<T> findAll = null;
        if (count > 0) {
            findAll = super.findAll(criteria, PageReq.getPageable(pageReq));
        }

        return ResultUtil.success(PageRes.toRes(findAll));

    }

    @Override
    public List<T> list(HashMap<String, Object> request) {
        //删除条件为空的值
        request.values().removeIf(value -> StringUtils.isEmpty(value));
        List<QueryCondition> list = new ArrayList<>();
        //默认查询未删除
        QueryCondition isDelete = QueryCondition.eq(BaseEntity.IS_DELETE, false);
        list.add(isDelete);
        if(request.size()>0){
            request.keySet().forEach(item -> {
                list.add(QueryCondition.like(item.toString(), request.get(item)));
            });
        }
        return super.findAll(list);
    }

    @Override
    //@Cacheable(value="JyCache" , key = "#p0.toString()",unless = "#result==null")
    public T findById(ID id) {
        Optional<T> findById = super.getById(id);
        T result = null;
        if (findById.isPresent()) {
            result = findById.get();
        } else {
            throw new ApplicationException("AE0001", id.toString());
        }
        afterSearch(result);
        return result;
    }

    @Override
    public long findCount(HashMap<String, Object> request) {
        //删除所有为空的条件
        request.values().removeIf(value -> StringUtils.isEmpty(value));
        if (request.size() > 0) {
            List<QueryCondition> list = new ArrayList<>();
            request.keySet().forEach(item -> {
                QueryCondition condition = QueryCondition.like(item, request.get(item).toString());
                list.add(condition);
            });
            //默认查询未删除
            QueryCondition condition = QueryCondition.eq(BaseEntity.IS_DELETE, false);
            list.add(condition);
            return super.count(list);
        } else {
            List<QueryCondition> list = new ArrayList<>();
            //默认查询未删除
            QueryCondition condition = QueryCondition.eq(BaseEntity.IS_DELETE, false);
            list.add(condition);
            return super.count(list);
        }
    }

    @Override
    @Transactional(propagation = Propagation.NESTED ,rollbackFor = Exception.class)
    public T create(T model) {
        preCreate(model);
        T t=null;
        try {
             t= super.save(model);
        } catch (ApplicationException ex) {
            throw ex;
        } catch (AppException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new ApplicationException("SE0005");
        }
        afterCreate(model,t);
        return t;
    }

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    public List<T> createList(List<T> list) {
        preCreateList(list);
        List<T> save=null;
        try {
            save= (List<T>) super.save(list);

        } catch (ApplicationException ex) {
            throw ex;
        } catch (AppException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new ApplicationException("SE0005");
        }

        return save;
    }

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    @CacheEvict(value="JyCache", key = "#model.id.toString()")
    public T update(T model) {
        //判断id是否存在
        T t = null;
        try {
            Method method = model.getClass().getMethod("getId");
            ID id = (ID) method.invoke(model);
            Optional<T> pages = super.getById(id);
            t = pages.get();
        } catch (Exception ex) {
            throw new ApplicationException("AE0001", model.getId().toString());
        }
        preUpdate(model, t);
        T save=null;
        //数据库修改
        try {
            BeanUtils.copyProperties(model, t, new String[]{"id", "isDelete", "creator", "createDate", "updater", "updateDate"});
            save= super.save(t);

        } catch (ApplicationException ex) {
            throw ex;
        } catch (AppException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new ApplicationException("SE0005");
        }
        afterUpdate(model,save);
        return save;
    }

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    @CacheEvict(value="JyCache", key="#p0['id'].toString()")
    public T updateState(HashMap<String, Object> map) {

        if (!map.containsKey(BaseEntity.ID) || map.get(BaseEntity.ID) == null || "".equals(map.get(BaseEntity.ID))) {
            throw new ApplicationException("AE0005", BaseEntity.ID);
        }
        Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        T t = null;
        try {
            T model = JSON.toJavaObject(new JSONObject(map), entityClass);
            ID id = null;
            Method method = model.getClass().getMethod("getId");
            id = (ID) method.invoke(model);
            Optional<T> byId = super.getById(id);
            t = byId.get();
            BeanConvertUtils.copyPropertiesIgnoreNull(model, t);
        } catch (Exception ex) {
            throw new ApplicationException("AE0001", map.get("id").toString());
        }
        return super.save(t);
    }

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    @CacheEvict(value="JyCache" , key = "#p0.toString()")
    public T del(ID id) {
        preDel(id);
        HashMap<String, Object> map = new HashMap<>();
        map.put("isDelete", true);
        map.put("id", id);
        T t = updateState(map);
        return t;
    }

    @Override
    @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
    @CacheEvict(value="JyCache", allEntries = true)
    public List<T> del(Map<String, ID[]> map) {
        //1.获取需要删除的集合
        ID[] ids = map.get("id");
        List<QueryCondition> condition = new ArrayList<>();
        condition.add(QueryCondition.in(BaseEntity.ID, Arrays.asList(ids)));
        //查询这些集合是否都在数据库中
        long size = super.count(condition);
        if ((int) size != ids.length) {
            throw new ApplicationException("AE0007");
        }
        //删除对应数据
        List<T> findAll = super.findAll(condition);
        findAll.forEach(item -> {
            item.setIsDelete(true);
        });
        List<T> save = (List<T>) super.save(findAll);
        return save;
    }


    /**
     * 移除查询条件为空的参数
     */
    public PageReq preBuildCriteria(QueryParam request) {
        PageReq req = new PageReq();
        Arrays.asList(PageReq.PO_PAGE, PageReq.PO_SIZE).forEach(item -> {
            if (request.containsKey(PageReq.PO_PAGE) && request.get(PageReq.PO_PAGE) instanceof Integer) {
                req.setPage(Integer.parseInt(request.get(PageReq.PO_PAGE).toString()));
                request.remove(PageReq.PO_PAGE);
            }
            if (request.containsKey(PageReq.PO_SIZE) && request.get(PageReq.PO_SIZE) instanceof Integer) {
                req.setSize(Integer.parseInt(request.get(PageReq.PO_SIZE).toString()));
                request.remove(PageReq.PO_SIZE);
            }
        });
        if(req.getPage()==null || req.getSize()==null){
            throw new ApplicationException("AE0008");
        }
        //删除所有为空的条件
        request.values().removeIf(value -> StringUtils.isEmpty(value));
        return req;
    }

    /**
     * 将每个查询参数拼接为condition条件
     * 默认为eq 需要其他条件需要重写
     *
     * @param request
     * @return
     */
    public List<QueryCondition> buildCriteria(QueryParam request) {
        List<QueryCondition> list = new ArrayList<>();
        request.keySet().forEach(item -> {
            QueryCondition condition = QueryCondition.eq(item, request.get(item));
            list.add(condition);
        });
        return list;
    }

    /**
     * id方法查询数据库后方法 用以补全数据
     * @param t
     */
    public void afterSearch(T t) {
    }

    /**
     * 新增之前自定义的方法 用以数据校验
     * @param t
     */
    public void preCreate(T t) {
    }

    /**
     * 新增之后的方法 用以多表更新
     * @param model
     * @param t
     */
    public void afterCreate(T model,T t) {
    }

    /**
     * 修改之前执行方法 用以补全数据和数据校验
     * @param model
     * @param id
     */
    public void preUpdate(T model, T id) {

    }

    /**
     * 修改之后执行方法 用以多表更新
     * @param model
     * @param t
     */
    public void afterUpdate(T model,T t) {

    }

    /**
     * preCreate 删除方法前逻辑处理 用以多表删除
     * @param id
     */
    public void preDel(ID id) {

    }

    public void preCreateList(List<T> list) {

    }
}